﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;

namespace AndreySmirnov.BLToolkitUtils.VSPackage
{
	public class SolutionEventsListener : IVsSolutionEvents
	{
		private readonly BLToolkitUtilsPackage m_package;

		public SolutionEventsListener(BLToolkitUtilsPackage package)
		{
			m_package = package;
		}

		private void EnumHierarchy(IVsHierarchy pHierarchy, uint itemId)
		{
			object pVar;
			var hr = pHierarchy.GetProperty(itemId, (int)__VSHPROPID.VSHPROPID_Name, out pVar);
			Debug.WriteLine(string.Format("[EnumHierarchy]: Node {0}", pVar));
			IntPtr nestedHierarchyObj;
			uint nestedItemId;
			Guid hierGuid = typeof(IVsHierarchy).GUID;
			hr = pHierarchy.GetNestedHierarchy(VSConstants.VSITEMID_ROOT, ref hierGuid, out nestedHierarchyObj, out nestedItemId);
			if (VSConstants.S_OK == hr && IntPtr.Zero != nestedHierarchyObj)
			{
				var nestedHierarchy = Marshal.GetObjectForIUnknown(nestedHierarchyObj) as IVsHierarchy;
				Marshal.Release(nestedHierarchyObj);    // we are responsible to release the refcount on the out IntPtr parameter
				if (nestedHierarchy != null)
				{
					EnumHierarchy(nestedHierarchy, itemId);
					// Display name and type of the node in the Output Window
					//EnumHierarchyItems(nestedHierarchy, nestedItemId, recursionLevel, false, visibleNodesOnly, processNodeFunc);
				}
			}
			else
			{
				hr = pHierarchy.GetProperty(itemId,
				                            (int) __VSHPROPID.VSHPROPID_FirstChild,
				                            out pVar);
				Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hr);
				uint childId = GetItemId(pVar);
				while (childId != VSConstants.VSITEMID_NIL)
				{
					EnumHierarchy(pHierarchy, childId);
					hr = pHierarchy.GetProperty(childId,
					   (int)__VSHPROPID.VSHPROPID_NextSibling,
					   out pVar);
					if (VSConstants.S_OK == hr)
					{
						childId = GetItemId(pVar);
					}
					else
					{
						Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(hr);
						break;
					}
				}
			}
		}
		/// <summary>
		/// Gets the item id.
		/// </summary>
		/// <param name="pvar">VARIANT holding an itemid.</param>
		/// <returns>Item Id of the concerned node</returns>
		private uint GetItemId(object pvar)
		{
			if (pvar == null) return VSConstants.VSITEMID_NIL;
			if (pvar is int) return (uint)(int)pvar;
			if (pvar is uint) return (uint)pvar;
			if (pvar is short) return (uint)(short)pvar;
			if (pvar is ushort) return (uint)(ushort)pvar;
			if (pvar is long) return (uint)(long)pvar;
			return VSConstants.VSITEMID_NIL;
		}

		public int OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded)
		{
			//EnumHierarchy(pHierarchy, VSConstants.VSITEMID_ROOT);
			var uiHierarchy = pHierarchy as IVsUIHierarchy;
			if (uiHierarchy != null)
			{
				Microsoft.VisualStudio.OLE.Interop.IServiceProvider sp;
				var hr = uiHierarchy.GetSite(out sp);
				var svcId = VSConstants.CLSID_VsUIHierarchyWindow;
				var intfId = typeof (IVsUIHierarchyWindow).GUID;
				IntPtr res;
				hr = sp.QueryService(ref svcId, ref intfId, out res);
				var uiHierarchyWindow = pHierarchy as IVsUIHierarchyWindow;
			}

			//EnumHierarchy(m_package.m_solution as IVsHierarchy);
			return VSConstants.S_OK;
		}

		public int OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel)
		{
			return VSConstants.S_OK;
		}

		public int OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved)
		{
			return VSConstants.S_OK;
		}

		public int OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy)
		{

			
			return VSConstants.S_OK;
		}

		public int OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel)
		{
			return VSConstants.S_OK;
		}

		public int OnBeforeUnloadProject(IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy)
		{
			return VSConstants.S_OK;
		}

		public int OnAfterOpenSolution(object pUnkReserved, int fNewSolution)
		{
			return VSConstants.S_OK;
		}

		public int OnQueryCloseSolution(object pUnkReserved, ref int pfCancel)
		{
			return VSConstants.S_OK;
		}

		public int OnBeforeCloseSolution(object pUnkReserved)
		{
			return VSConstants.S_OK;
		}

		public int OnAfterCloseSolution(object pUnkReserved)
		{
			return VSConstants.S_OK;
		}
	}
}
